/*
 *  mih_sap.c
 *  MIHF
 *
 *  Created by injae song on 11. 3. 4..
 *  Copyright 2011 KyungHee Univ. All rights reserved.
 *
 */

#include "mih_sap.h"

void mih_sap_init(mihf* mih)
{

	warn("=                                                 =\n");

	warn("==== MIH Init for MIH user                        =\n");

	warn("=                                                 =\n");

	int sockfd;  /* listen on sock_fd, new connection on new_fd */
	int len=-1;
	struct sockaddr_in my_addr;    /* my address information */
	
	sockfd = socket(AF_INET, SOCK_STREAM, 0); /* do some error checking! */
	
	if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&len,sizeof(len))==-1) {
		exit(2);
	}
	
	fcntl(sockfd, F_SETFL, O_NONBLOCK);
	my_addr.sin_family = AF_INET;         /* host byte order */
	my_addr.sin_port = htons(MIH_USER_PORT);     /* short, network byte order */
	my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */
	bzero(&(my_addr.sin_zero), 8);        /* zero the rest of the struct */
	
	/* don't forget your error checking for these calls: */
	bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
	
	listen(sockfd, MAX_LISTEN);
	
	event_set( &mih->ev_accept_user, sockfd, EV_READ|EV_PERSIST, mih_sap_connection_accept, (void*) mih);
	
	event_add( &mih->ev_accept_user, NULL);
}

void mih_sap_connection_accept(int sockfd, short event , void *ev) {
	
	struct sockaddr their_addr; /* connector's address information */
	
	mihf *mih= (mihf*) ev;
	
	mih_user *user;
	
	uint sin_size;
	
	int new_fd;
	
	sin_size = sizeof(struct sockaddr_in);
	
	new_fd = accept(sockfd, &their_addr, &sin_size);
	
	if (new_fd == -1) 
	{
#ifdef Debug
		warn("new user connection error\n");
#endif
		exit(0);
	}
	
	user = malloc(sizeof(mih_user));
	user->fd = new_fd;
	user->ev_buf = bufferevent_new(new_fd, mih_sap_read_handler, mih_sap_write_handler, mih_sap_error_handler, (void *) user);
	bufferevent_enable(user->ev_buf, EV_READ);	
	
	if(user->ev_buf == NULL) 
	{
		warn("new mih user on fd = %d but can't create buffer\n", new_fd);

		exit(0);
	}
	
	list_ins_next(&mih->User_table,list_tail(&mih->User_table),(void*) user);

	warn("new mih user on fd = %d\n",new_fd);

	return;
}

void mih_sap_read_handler(struct bufferevent *bev, void *arg)
{
	warn("[mihf_sap_read]\n");
	mih_user *user = arg;
	mih_message* mih_msg;
	char *buffer;
	
	size_t len = EVBUFFER_LENGTH(bev->input);
	buffer = malloc(len);
	
	bzero(buffer, len);
	
	// Read MIH header
	bufferevent_read(bev, buffer, len);
	
	mih_msg = mih_message_parse(buffer);
	
	mih_sap_dispatch(mih_msg, user);
	
	return;
}

void mih_sap_send_message(mih_message *msg, mih_user *user)
{
	
	char *mih_frame;
	
	mih_frame = mih_message_serialize(msg);
	
	warn("sending message to mih user\n");
	
	bufferevent_write(user->ev_buf, mih_frame, MIH_HEADER_SIZE + msg->header->payloadlength);
	
	return;
}

void mih_sap_write_handler(struct bufferevent *bev, void *arg) {
	
}

void mih_sap_error_handler(struct bufferevent *bev, short what, void *arg) {
	
	mih_user *user = arg;
	
	if (what & EVBUFFER_EOF)
		warn("#%d user close\n", user->fd);
	else if (what == (EVBUFFER_ERROR | EVBUFFER_READ))
		warn("#%d user reset connection\n", user->fd);
	else if (what & EVBUFFER_TIMEOUT)
		warn("#%d user timeout\n", user->fd);
	else if (what & EVBUFFER_WRITE)
		warn("#%d user write error\n", user->fd);
	else
		warn("#%d abnormal user error\n", user->fd);
	
	//free_mih_connection(s);
	
	return;
}